<?php

namespace StudyBuddy;

/**
 * Class to perform html to plaintext
 * transformation
 *
 * Use it like this:
 *
 * $oHTML2TEXT = H2t::factory($inputHTML);
 * echo $oHTML; // will output formatted plaintext
 *
 * or to get the result as a string call getText() method
 *
 * $oHTML2TEXT = H2t::factory($inputHTML);
 * $text = $oHTML->getText(); // will return formatted plaintext
 *
 */
class H2t {

    /**
     * Configuration array
     * for the html_tidy
     *
     * @var array
     */
    protected $aTidyConfig = array(
        'clean' => true,
        'indent' => true,
        'output-xhtml' => true,
        'wrap' => 0);

    /**
     * Object of type DOMDocument
     * that holds the input html
     *
     * @var object
     */
    protected $oInputDom;

    /**
     * Object of type XSLProcessor
     *
     * @var object
     */
    protected $oXSL;

    /**
     * Location of template file
     * must point to plaintext.xsl file
     *
     * @var string
     */
    protected $templateFile = 'plaintext.xsl';

    /**
     * Constructor, cannot be called
     * directly, only via factory!
     *
     * @return void
     */
    protected function __construct() {
        if (!extension_loaded('xsl')) {

            throw new Exception('php_xsl extension not loaded. If you are on Windows, please uncomment ;extension=php_xsl.dll in your php.ini');
        }

        $this->oInputDom = new \DOMDocument();
        $this->oInputDom->recover = true;
        $this->makeXslProcessor();
    }

    /**
     * Factory method to make the object,
     * load html string
     * object will be ready, can just
     * call echo $obj to get result of transformation
     *
     * @param string $sHtml input html string
     * @return object of this class
     */
    public static function factory($sHtml) {
        $o = new self();
        $o->loadHtml($sHtml);

        return $o;
    }

    /**
     * Loads the input html string
     * into the DOMDocument object
     * if tidy is available it will first
     * run the input through tidy
     * to fix the html string (in case it's not a valid html)
     *
     * @important the DOMDocument
     * expects the html to be in ISO-8859-1 charset
     * but will use the meta tag
     * <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
     *
     * So if your html string is in utf-8 format, then it must contain this header
     * and like this:
     *
     * <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
      "http://www.w3.org/TR/REC-html40/loose.dtd">
      <head>
      <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
      </head>
      <body><div>'.$sHtml.'</div></body></html>
     *
     * OR it must just be in ISO-8859-1 format but then
     * it MUST NOT contain any Content-Type meta tag
     * or correctly have the charset set to ISO-8859-1
     *
     * @param string $sHtml
     *
     * @return object $this
     *
     * @throws HTML2TextException if unable to load html string
     * into DOM
     */
    public function loadHtml($sHtml) {

        if (extension_loaded('tidy')) {
            $tidy = new \tidy;
            $tidy->parseString($sHtml, $this->aTidyConfig);
            $tidy->cleanRepair();
            $sHtml = $tidy->value;
        }

        if (false === @$this->oInputDom->loadHTML($sHtml)) {
            throw new HTML2TextException('Invalid input: this is not valid HTML: ' . $sHtml);
        }

        $this->oInputDom->normalizeDocument();

        return $this;
    }

    protected function makeXslProcessor() {
        $xsl = new \DOMDocument;
        $tpl = STUDYBUDDY_PATH . DIRECTORY_SEPARATOR . $this->templateFile;
        if (!is_file($tpl)) {
            throw new HTML2TextException('XSL template not found here: ' . $tpl);
        }


        if (!$xsl->load($tpl)) {
            throw new HTML2TextException('Unable to load xsl template: ' . $this->templateFile);
        }

        $this->oXSL = new \XSLTProcessor;
        $this->oXSL->registerPHPFunctions();
        $this->oXSL->importStyleSheet($xsl);

        return $this;
    }

    /**
     * Performes the transformation
     * and sets the $this->sOutput
     * wraps text so that lines
     * are not wider than 75 chars
     *
     * @return string output text
     * @throws HTML2TextException if unable to transform to text
     */
    public function getText() {
        if (false === $text = $this->oXSL->transformToXML($this->oInputDom)) {
            throw new HTML2TextException('Unable to transform to text');
        }

        return wordwrap($text);
    }

    /**
     * Magic method to enable echoing
     * of this object
     *
     * @return string result of getText()
     */
    public function __toString() {
        return $this->getText();
    }

}

?>
